package boot

import (
	"context"
	"flag"
	"fmt"
	"gitee.com/xfrm/middleware/xlog"
	"gitee.com/xfrm/starter/boot/bootservice"
	"gitee.com/xfrm/starter/boot/server"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var GlobalServer server.Server

type EnumCfgType string

const (
	CfgType_YAML EnumCfgType = "yaml"
	CfgType_ETCD EnumCfgType = "etcd"
)

type Boot struct {
	services               map[string]bootservice.Service
	preServiceDriverFuncs  []func(ctx context.Context, server server.Server) error
	postServiceDriverFuncs []func(ctx context.Context, server server.Server) error
	bootConf               *BootConfig
	sbase                  server.Server
}

type BootConfig struct {
	Sgroup  string      `json:"sgroup"`
	Sname   string      `json:"sname"`
	Cfgtype EnumCfgType `json:"cfgtype"` // yaml, etcd 均会使用约定的路径地址
	Cfgroot string      `json:"cfgroot"`
	IsTest  bool        `json:"istest"`
}

var defaultBoot = NewBoot()

//bootconf 优先级高于命令行
func Run(bootConf *BootConfig) error {
	return defaultBoot.mergerConfig(bootConf).AppendPreServiceDriverFuncs(func(ctx context.Context, server server.Server) error {
		//把当前启动的服务，外呼出来
		GlobalServer = server
		return nil
	}).Run()
}

func InitTest(bootConf *BootConfig) error {
	bootConf.IsTest = true
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		AppendPostServiceDriverFuncs(func(ctx context.Context, sb server.Server) error {
			wg.Done()
			return nil
		})
		err := Run(bootConf)
		if err != nil {
			fmt.Printf("################## err:%v\n", err)
		}
	}()
	wg.Wait()
	time.Sleep(time.Second)
	fmt.Println("-----------------------------  INIT OK  -----------------------------")
	return nil
}

//额外增加一些启动服务
func AppendService(services map[string]bootservice.Service) {
	defaultBoot.AppendService(services)
	return
}

//额外增加 前置初始化函数
func AppendPreServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) {
	defaultBoot.AppendPreServiceDriverFuncs(initfns...)
	return
}

//额外增加 后置初始化函数
func AppendPostServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) {
	defaultBoot.AppendPostServiceDriverFuncs(initfns...)
	return
}
func NewBoot() *Boot {
	boot := &Boot{
		services:               make(map[string]bootservice.Service),
		preServiceDriverFuncs:  make([]func(ctx context.Context, server server.Server) error, 0),
		postServiceDriverFuncs: make([]func(ctx context.Context, server server.Server) error, 0),
	}
	return boot
}
func (m *Boot) initConfig() {
	m.parseFlag()
}

func (m *Boot) mergerConfig(highPriority *BootConfig) *Boot {
	m.initConfig()
	if highPriority == nil {
		return m
	}
	if highPriority.Sgroup != "" {
		m.bootConf.Sgroup = highPriority.Sgroup
	}
	if highPriority.Sname != "" {
		m.bootConf.Sname = highPriority.Sname
	}
	if highPriority.Cfgtype != "" {
		m.bootConf.Cfgtype = highPriority.Cfgtype
	}
	if highPriority.Cfgroot != "" {
		m.bootConf.Cfgroot = highPriority.Cfgroot
	}
	return m
}
func (m *Boot) parseFlag() {
	var sgroup, cfgtype, sname, cfgroot string
	flag.StringVar(&sgroup, "sgroup", "", "sgroup name")
	flag.StringVar(&sname, "sname", "", "sname name")
	flag.StringVar(&cfgtype, "cfgtype", "", "cfgtype: yaml, etcd ")
	flag.StringVar(&cfgroot, "cfgroot", "", "cfgroot: defautl /opt/conf ")
	flag.Parse()
	// 优先启动参数
	if sgroup == "" {
		sgroup = os.Getenv("SGROUP")
	}
	if sname == "" {
		sname = os.Getenv("SNAME")
	}
	if cfgtype == "" {
		cfgtype = os.Getenv("CFGTYPE")
	}
	m.bootConf = &BootConfig{
		Sgroup:  sgroup,
		Sname:   sname,
		Cfgtype: EnumCfgType(cfgtype),
		Cfgroot: cfgroot,
	}

}
func (m *Boot) AppendService(services map[string]bootservice.Service) *Boot {
	for k, v := range services {
		m.services[k] = v
	}
	return m
}
func (m *Boot) AppendPreServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) *Boot {
	m.preServiceDriverFuncs = append(m.preServiceDriverFuncs, initfns...)
	return m
}
func (m *Boot) AppendPostServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) *Boot {
	m.postServiceDriverFuncs = append(m.postServiceDriverFuncs, initfns...)
	return m
}
func (m *Boot) Run() error {
	fun := "Boot.Run -->"

	if err := m.initServer(); err != nil {
		return err
	}
	xlog.Infof(context.Background(), "%s awaiting signal", fun)
	m.awaitSignal()
	return nil
}
func (m *Boot) initServer() error {
	//fun:="Boot.initServer -->"
	ctx := context.Background()
	switch m.bootConf.Cfgtype {
	case CfgType_YAML:
		yamlServer := server.NewYamlServer(m.bootConf.Sgroup, m.bootConf.Sname, m.bootConf.Cfgroot)
		yamlServer.AppendService(m.services)
		yamlServer.AppendPreServiceDriverFuncs(m.preServiceDriverFuncs)
		yamlServer.AppendPostServiceDriverFuncs(m.postServiceDriverFuncs)
		m.sbase = yamlServer
	case CfgType_ETCD:
	default:
		return fmt.Errorf("unsupport config type: %s", m.bootConf.Cfgtype)
	}
	//服务启动
	if err := m.sbase.Startup(ctx); err != nil {
		return err
	}
	return nil
}

func (m *Boot) awaitSignal() {
	c := make(chan os.Signal, 1)
	ctx := context.Background()
	signals := []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE}
	signal.Notify(c, signals...)

	for {
		select {
		case s := <-c:
			xlog.Infof(ctx, "receive a signal:%s", s.String())
			if s.String() == syscall.SIGTERM.String() {
				xlog.Infof(ctx, "receive a signal: %s, stop server", s.String())
				m.sbase.Shutdown(ctx)
				<-(chan int)(nil)
			}
		}
	}

}
